package com.example.laundry.service;

import com.example.laundry.dto.*;
import com.example.laundry.entity.UserEntity;
import com.example.laundry.exception.AuthenticationException;
import com.example.laundry.exception.ResourceNotFoundException;
import com.example.laundry.exception.ResourceAlreadyExistsException;
import com.example.laundry.repository.UserRepository;
import com.example.laundry.security.JwtTokenProvider;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;

@Service
@RequiredArgsConstructor
@Slf4j
public class AuthServiceImpl implements AuthService {

    private final AuthenticationManager authenticationManager;
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    private final JwtTokenProvider jwtTokenProvider;

    @Override
    public JwtResponseDto authenticateUser(UserLoginDto loginDto) {
        try {
            Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                    loginDto.getUsername(),
                    loginDto.getPassword()
                )
            );

            SecurityContextHolder.getContext().setAuthentication(authentication);
            String jwt = jwtTokenProvider.generateToken(authentication);
            
            UserEntity user = userRepository.findByUsername(loginDto.getUsername())
                .orElseThrow(() -> new UsernameNotFoundException("User not found: " + loginDto.getUsername()));
            
            log.info("User {} successfully authenticated", loginDto.getUsername());
            
            return JwtResponseDto.builder()
                .token(jwt)
                .id(user.getId())
                .username(user.getUsername())
                .email(user.getEmail())
                .roles(user.getRoles())
                .build();
        } catch (BadCredentialsException e) {
            log.warn("Authentication failed for user {}", loginDto.getUsername());
            throw new AuthenticationException("Invalid credentials");
        }
    }

    @Override
    @Transactional
    public UserResponseDto registerUser(UserRegisterDto registerDto) {
        if (userRepository.existsByUsername(registerDto.getUsername())) {
            log.warn("Registration failed: Username {} already exists", registerDto.getUsername());
            throw new ResourceAlreadyExistsException("Username is already taken");
        }

        if (userRepository.existsByEmail(registerDto.getEmail())) {
            log.warn("Registration failed: Email {} already exists", registerDto.getEmail());
            throw new ResourceAlreadyExistsException("Email is already in use");
        }

        UserEntity user = UserEntity.builder()
            .username(registerDto.getUsername())
            .email(registerDto.getEmail())
            .password(passwordEncoder.encode(registerDto.getPassword()))
            .roles(Collections.singleton("ROLE_USER"))
            .enabled(true) // 默认启用用户
            .build();

        UserEntity savedUser = userRepository.save(user);
        
        log.info("User {} registered successfully", savedUser.getUsername());

        return UserResponseDto.builder()
            .id(savedUser.getId())
            .username(savedUser.getUsername())
            .email(savedUser.getEmail())
            .roles(savedUser.getRoles())
            .enabled(savedUser.isEnabled())
            .createdAt(savedUser.getCreatedAt())
            .build();
    }

    @Override
    public UserResponseDto getCurrentUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        
        // 检查是否为匿名用户或未认证
        if (authentication == null || !authentication.isAuthenticated() || 
            authentication.getPrincipal() instanceof String) {
            log.warn("Unauthenticated access to getCurrentUser()");
            throw new AuthenticationException("Authentication required");
        }
        
        String username = authentication.getName();
        
        UserEntity user = userRepository.findByUsername(username)
            .orElseThrow(() -> new ResourceNotFoundException("User not found: " + username));
        
        return UserResponseDto.builder()
            .id(user.getId())
            .username(user.getUsername())
            .email(user.getEmail())
            .roles(user.getRoles())
            .enabled(user.isEnabled())
            .createdAt(user.getCreatedAt())
            .build();
    }
}